﻿using RndMaterialDisposalService.Attrbutes;
using RndMaterialDisposalService.Cache;
using RndMaterialDisposalService.Helper;
using RndMaterialDisposalService.Models;
using RndMaterialDisposalService.Repository;
using RndMaterialDisposalService.Services.Interface;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Linq;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
using Microsoft.Extensions.Caching.Memory;
using static System.Net.WebRequestMethods;
using RndMaterialDisposal.Extensions.Authorization;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

namespace RndMaterialDisposalService.Services
{
    /// <summary>
    /// 写JwtHelper比较好，后续改
    /// </summary>
    [NAutowired(Lifecycle.Singleton)]
    public class TokenService : ITokenService
    {
        private readonly IConfiguration _configuration;
        private ICacheContext _cacheContext;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_dbContext"></param>
        public TokenService(IConfiguration configuration,ICacheContext cacheContext)
        {
            _configuration = configuration;
            _cacheContext = cacheContext;
        }

        /// <summary>
        /// 生产token
        /// </summary>
        /// <param employeeNumber="员工号"></param>
        /// <returns></returns>
        public async Task<string> CreateToken(DateTime expireTime)
        {
            
            // 1. 定义需要使用到的Claims
            var claims = new[]
            {
                new Claim(ClaimTypes.Name, "zhangsan"), //HttpContext.User.Identity.Name，换zhangsan测试不同权限
                new Claim(ClaimTypes.Role, "r_admin"), //HttpContext.User.IsInRole("r_admin")
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),//（JWT ID）编号
                new Claim("Username", "Admin"),

                //实际程序我们肯定不是这样实现的，这里只是简易示例
                new Claim("Permission", UserPermission.UserCreate),
                new Claim("Permission", UserPermission.UserUpdate)
            };
            // 2. 从 appsettings.json 中读取SecretKey
            var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"]));
            // 3. 选择加密算法
            var algorithm = SecurityAlgorithms.HmacSha256;
            // 4. 生成Credentials
            var signingCredentials = new SigningCredentials(secretKey, algorithm);
            // 5. 根据以上，生成token
            var jwtSecurityToken = new JwtSecurityToken(
                _configuration["Jwt:Issuer"],     //Issuer
                _configuration["Jwt:Audience"],   //Audience
                claims,                          //Claims,
                DateTime.Now,                    //notBefore
                expireTime,    //expires
                signingCredentials               //Credentials
            );
            // 6. 将token变为string
            var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
            return token;
        }

        public async Task<bool> VerifyJwtToken(string token)
        {
            ClaimsPrincipal principal = null;
            //对称秘钥
            SecurityKey securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"]));
            //校验token
            var validateParameter = new TokenValidationParameters()
            {
                ValidateLifetime = true,
                ValidateAudience = true,
                ValidateIssuer = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = _configuration["Jwt:Issuer"], //发行人Issuer,
                ValidAudience = _configuration["Jwt:Audience"], //订阅人Audience,
                IssuerSigningKey = securityKey,
                ClockSkew = TimeSpan.Zero//校验过期时间必须加此属性
            };
            //不校验，直接解析token
            //jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token1);
            bool success = false;
            try
            {
                //校验并解析token,validatedToken是解密后的对象
                principal = new JwtSecurityTokenHandler().ValidateToken(token, validateParameter, out SecurityToken validatedToken);
                //获取payload中的数据 
                //var jwtPayload = ((JwtSecurityToken)validatedToken).Payload.SerializeToJson(); 
                success = true;

            }
            catch (SecurityTokenExpiredException ex)
            {
                //表示过期，在做RefreshToken时候不校验过期。
                success = false;
            }
            catch (SecurityTokenException ex)
            {
                //表示token错误
                success = false;
            }
            catch (Exception ex)
            {
                success = false;
            }
            return success;
        }

        /// <summary>
        /// 获取企业微信token  只在同步主数据时候用的token
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetWeixinToken()
        {
           var acessTokenCur = _cacheContext.Get<string>("wxAcessToken");
           var expireTimeCur = _cacheContext.Get<DateTime>("wxExpireTime");
            if (acessTokenCur != null && expireTimeCur!=null && DateTime.Now < expireTimeCur)
            {
                return acessTokenCur;
            }
            else
            {
                var result = await GetQiYiWeixinToken();
                return result.acessToken;
            }
        }

        private async Task<(string acessToken, DateTime expireTime)> GetQiYiWeixinToken()
        {
            var url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
            var data = new { corpid = "wx080f78ecd8c15f53", corpsecret = "BqfPl7xEMaoPuKo2y4drjBbb8GUpahGAy88xvyENOaA" };
            var result = await HttpHelper.PostAsync(url, JsonSerializer.Serialize(data));
            var jsonObj = JObject.Parse(result);
            var acessTokenCur = jsonObj["access_token"].ToString();
            //int expiresin = int.Parse(jsonObj["expires_in"].ToString());
            var expireTimeCur = DateTime.Now.AddSeconds(7200);
            //设置绝色过期
            //_cacheContext.Set("wxAcessToken", acessTokenCur, DateTime.Now.AddDays(2));
            //_cacheContext.Set("wxExpireTime", expireTimeCur, DateTime.Now.AddDays(2));
            //设置滑动过期
            _cacheContext.Set("wxAcessToken", acessTokenCur, new MemoryCacheEntryOptions()
            {
                //设置滑动过期
                SlidingExpiration = new TimeSpan(2,0,0),
                Priority = CacheItemPriority.NeverRemove
            });


            return (acessTokenCur, expireTimeCur);
        }


    }
}
